#include "http_server/http_session.hpp"
#include <iostream>
#include <sstream>

HttpSession::HttpSession(boost::asio::ip::tcp::socket socket)
    : socket_(std::move(socket))
{
}

void HttpSession::start()
{
    do_read();
}

void HttpSession::do_error(const boost::system::error_code &ec)
{
    std::cerr << "Error: " << ec.message() << " (Code: " << ec.value() << ")" << std::endl;
}

void HttpSession::do_read()
{
    // 【关于 enable_shared_from_this 的疑问】
    // 由于异步操作是非阻塞的，
    // 在操作系统的异步操作期间，指向当前HttpSession对象的shared_ptr（也就是在HttpServer中创建的std::make_shared<HttpSession>(std::move(new_socket))）可能会销毁，导致对象析构，
    // 导致回调函数中的指针变为悬空指针，引发未定义行为，
    // 为了防止当前HttpSession对象析构，应该增加指向当前对象的shared_ptr，使引用计数+1
    // 保证后续异步操作期间、异步操作之后的回调函数中，当前HttpSession对象没有被析构。
    // 查一下 “异步保活机制”

    auto self = shared_from_this(); // 获取一个shared_ptr指向当前对象，引用计数+1，在异步操作的回调函数的闭包中，捕获了self
    std::cout << "do_read() : use_count: " << self.use_count() << std::endl;

    // 异步读取来自客户端的请求数据，直到遇到指定的分隔符，这个函数对于读取以某个分隔符结尾的数据或者读取特定模式的数据非常有用
    boost::asio::async_read_until(
        socket_,                                                       // 读取的数据流，这里读的是网络流
        read_buffer_,                                                  // 读取后放到缓冲区里
        "\r\n\r\n",                                                    // 分隔符
        [this, self](boost::system::error_code ec, std::size_t length) // 读取完毕后调用
        {
            // auto self = shared_from_this()保证了此处至少引用计数是1，指向的对象没有被销毁
            std::cout << "回调函数() : use_count: " << self.use_count() << std::endl;

            if (ec) // 错误处理
            {
                do_error(ec);
                return;
            }

            // 调试信息，简单打印一下HTTP请求的第一行
            std::istream request_stream(&read_buffer_);
            std::string request_line;
            std::getline(request_stream, request_line);
            std::string method, uri, version;
            std::istringstream request_line_stream(request_line);
            request_line_stream >> method >> uri >> version;
            std::cout << "Request: " << method << " " << uri << " " << version << std::endl;

            // 做出简单的相应
            std::string response =
                "HTTP/1.1 200 OK\r\n"
                "Content-Type: text/plain\r\n"
                "Content-Length: 13\r\n"
                "\r\n"
                "Hello, World!";

            do_write(response);
        });
}

// 可以在此做响应的业务逻辑
void HttpSession::do_write(const std::string &response)
{
    auto self = shared_from_this();

    // 异步发送 HTTP 响应数据
    boost::asio::async_write(
        socket_,                                                       // 写入的数据流，这里是网络流
        boost::asio::buffer(response),                                 // 要写的数据
        [this, self](boost::system::error_code ec, std::size_t length) // 写完后调用
        {
            if (ec) // 错误处理
            {
                do_error(ec);
                return;
            }

            // 调试信息，简单打印一下
            std::cout << "Data has been sended.\n";

            // 为了简化程序，每个请求/响应对使用一个新的 TCP 连接。响应发送完毕后，服务器关闭连接。（HTTP/1.0 短连接）
            socket_.shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
            socket_.close();
        });
}
